library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;

entity PGblock is
generic (	N : integer;
		M : integer);						-- M = log2 (N)
port (	p_in  : in  std_logic_vector(N-1 downto 0);
		g_in  : in  std_logic_vector(N-1 downto 0);
		C_out : out std_logic_vector((N/4)-1 downto 0)
);
end PGblock;

architecture Structural of PGblock is

component blackblock10 is
port (	P11	: in   std_logic;
		G11	: in   std_logic;
		P00	: in   std_logic;
		G00	: in   std_logic;
		G10	: out std_logic;
		P10	: out std_logic
);
end component;

subtype matrix_address is integer range -1 to M-3;
type matrix is array(matrix_address) of std_logic_vector(N/4-1 downto 0);

signal G : matrix;
signal P : matrix;

signal P0 : std_logic_vector(N/2-1 downto 0);
signal G0 : std_logic_vector(N/2-1 downto 0);

begin

C_out <= G(M-3);

FirstRow : for j in 0 to N/2-1 generate
	cols0 : blackblock10 port
	map (	P11 => p_in(2*j+1),
			G11 => g_in(2*j+1),
			P00 => p_in(2*j),
			G00 => g_in(2*j),
			G10 => G0(j),
			P10 => P0(j)
		);
end generate FirstRow;

SecondRow : for j in 0 to N/4 -1 generate
	cols1 : blackblock10 port 
	map (	P11 => P0(2*j+1),
			G11 => G0(2*j+1),
			P00 => P0(2*j),
			G00 => G0(2*j),
			G10 => G(-1)(j),
			P10 => P(-1)(j)
		);
end generate SecondRow;

OtherRows : for i in 0 to M-3 generate
	Cols: for j in 0 to N/4 - 1 generate
		TestEven: if ((j/(2**i)) mod 2) = 0 generate
			P(i)(j) <= P(i-1)(j);
			G(i)(j) <= G(i-1)(j);
		end generate TestEven;
	TestOdd: if ((j/(2**i)) mod 2) /= 0 generate
		BBi : blackblock10 port
		map (	P11 => P(i-1)(j),
				G11 => G(i-1)(j),
				P00 => P(i-1)(2**i - 1 + 2**(i+1)*(j/(2**(i+1)))),
				G00 => G(i-1)(2**i - 1 + 2**(i+1) * (j/(2**(i+1)))),
				G10 => G(i)(j),
				P10 => P(i)(j)
			);
		end generate TestOdd;
	end generate Cols;
end generate OtherRows;        

end Structural;
